﻿//--------------------------------------------------------------------------
// 
//  Copyright (c) Chili Software.  All rights reserved. 
// 
//  File: ObjectContext.cs
//
//  Description: Loads and persists changes on persistent objects.
// 
//--------------------------------------------------------------------------

using System;
using System.Data;
using System.Collections.Generic;
using System.Reflection;
using Chili.Opf3.Relations;
using Chili.Opf3.Storages;
using Chili.Opf3.Concurrency;
using Chili.Opf3.Query;
using Chili.Opf3.Caching;
using Chili.Opf3.Mapping;
using System.Diagnostics;

namespace Chili.Opf3
{
	/// <summary>
	/// Represents the context that manages, loads, saves and deletes persistent objects.
	/// </summary>
	/// <remarks>
	///		<para>
	///			<strong>Thread Safety:</strong> Any public static members of this type are thread safe. 
	///			Any instance members are not guaranteed to be thread safe.
	///		</para>
	/// 	<para>This class is the main point when loading, saving and deleting persistent
	///     objects to/from the storage. Whenever objects are loaded from the storage you need
	///     (<strong>don't use directly the storage</strong>) to request them by using an
	///     ObjectContext class. The class contains specialized methods (all generic) allowing
	///     the user to get single objects, a list of objects or an
	///     <see cref="Opf3.ObjectSet{T}">ObjectSet</see> from the storage. Each object can
	///     also be marked for deletion by using the
	///     <see cref="Opf3.ObjectContext.MarkForDeletion">MarkForDeletion</see> method of
	///     the ObjectContext. An object that has been marked for deletion is deleted the next
	///     time the changes are persisted to the storage.</para>
	/// 	<para>When setting up an instance of the ObjectContext class you have to pass to
	///     the constructor an instance of a class that implements the
	///     <see cref="Opf3.Storages.IStorage">IStorage</see> interface. Those classes are so
	///     called "storages". They encapsulate a physical storage (like a database or anything
	///     else...) and each ObjectContext instance operates on one of those storages. The
	///     framework ships with a few storages for databases such as the
	///     <see cref="Opf3.Storages.Oracle.OracleStorage">OracleStorage</see>, the
	///     <see cref="Opf3.Storages.MsSql.MsSqlStorage">MsSqlStorage</see> and the
	///     <see cref="Opf3.Storages.OleDb.OleDbStorage">OleDbStorage</see> to mention any of
	///     them. When setting up the storage you have not to open it in any kind. This is done
	///     by the framework: the connections to the storage are handled by the classes
	///     internally (in the storages coming with the framework the ADO.NET connection pool
	///     is used).</para>
	/// 	<para>Be aware that persistent objects loaded within one ObjectContext "life" in
	///     this ObjectContext. This means that the ObjectContext manages internally the state
	///     of the object (see <see cref="Opf3.ObjectInfo">ObjectInfo</see>). This could cause
	///     problems when loading the persistent object with one ObjectContext and saving it on
	///     another that works on the same storage. To avoid this problem persistent objects
	///     that are loaded on one ObjectContext and saved on another have to implement the
	///     <see cref="Opf3.ISelfContainingObject">ISelfContaining</see> interface. Persistent
	///     objects implementing this interface are ObjectContext independent and can be saved
	///     and loaded on any instance of an ObjectContext (if all of them are accessing the
	///     same storage). When implementing the interface the state is managed by the
	///     persisten object itself! The
	///     <see cref="Opf3.ISelfContainingObject">ISelfContainingObject</see> interface is
	///     also implemented if a persistent object is remoted over the network or persisted
	///     (serialized) to any kind of storage for further use.</para>
	/// 	<para>Before using an ObjectContext you should also connect an instance of a class
	///     that implements the
	///     <see cref="Opf3.Concurrency.IConcurrencyManager">IConcurrencyManager</see>
	///     interface with the class by setting the
	///     <see cref="Opf3.ObjectContext.ConcurrencyManager">ConcurrencyManager</see> property
	///     of the ObjectContext. If the program works on a storage that is locally installed
	///     and if it is the only program working on that storage you could use no
	///     <see cref="Opf3.Concurrency.IConcurrencyManager">IConcurrencyManager</see>. But
	///     it's not recommended! A concurrency manager checks if the persistent object to save
	///     has been changed by anybody else in the meantime (while being in memory). If
	///     somebody else changed the object in the storage you get a
	///     <see cref="Opf3.Concurrency.ConcurrencyException">ConcurrencyException</see>. With
	///     this excpetion you can inform the user that somebody else altered the object in the
	///     meantime. The object could then be reloaded or saved in any other place.</para>
	/// 	<para>To save the changes of your objects you have to use
	///     <see cref="Opf3.ObjectContext.PersistChanges{T}(T)">PersistChanges</see>
	///     of the ObjectContext. The method allows you to persist single objects or objects
	///     that implement the <see cref="Opf3.ICustomPersister">ICustomPersister</see>
	///     interface. This interface is implemented by classes that persist more then one
	///     object. For an example look at the <see cref="Opf3.ObjectSet{T}">ObjectSet</see>
	///     class.</para>
	/// 	<para>If the class implementing the
	///     <see cref="Opf3.Storages.IStorage">IStorage</see> interface implements also the
	///     <see cref="Opf3.Storages.ITransactionStorage">ITransactionStorage</see> interface
	///     the ObjectContext supports also Transactions on that storage. Use
	///     <see cref="Opf3.ObjectContext.StartTransaction()">StartTransaction</see>,
	///     <see cref="Opf3.ObjectContext.Rollback">Rollback</see> and
	///     <see cref="Opf3.ObjectContext.Commit">Commit</see> for transaction management.
	///     <strong>Please don't use directly the methods exposed by the
	///     storage.</strong></para>
	/// 	<para>The ObjectContext returns an
	///     <see cref="Opf3.ObjectSearcher{T}">ObjectSearcher</see> when invoking
	///     <see cref="Opf3.ObjectContext.GetObjectSearcher{T}">GetObjectSearcher</see>. You could
	///     use this class to specify your search queries for a given object type. For more
	///     information about creating your own
	///     <see cref="Opf3.ObjectSearcher{T}">ObjectSearcher</see> check out the
	///     <see cref="Opf3.ObjectSearcher{T}">ObjectSearcher</see> class.</para>
	/// </remarks>
	/// <example>
	///     The following example shows how to use the functionality of the ObjectContext
	///     class. 
	///     <code lang="CS">
	/// [Persistent("USER")]
	/// public class User
	/// {
	///     private string _name = null;
	///  
	///     [Field("NAME")]
	///     public string Name
	///     {
	///         get { return _name; }
	///         set { _name = value; }
	///     }
	///  
	///     // ... Other properties and fields.
	/// }
	///  
	/// // ... Other code
	///  
	/// // Creates a new ObjectContext that uses an MsSql Server as storage.
	/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
	///     "localhost", "application"));
	/// // Set the MD5 Concurrency Manager.
	/// context.ConcurrencyManager = new Md5ConcurrencyManager();
	///  
	/// // Loads a user object from the storage.
	/// User user = context.GetObject&lt;User&gt;("Id = {0}", "1");
	/// // Loads an ObjectSet of user and sorts them by Name.
	/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;
	///     ("Name like {0} SortBy Name Asc", "%mith%");
	/// // Change the name of each user.
	/// foreach(User user in objectSet)
	/// {
	///     user.Name = "Smith the II";
	/// }
	///  
	/// // Start a transaction on the ObjectContext.
	/// context.StartTransaction();
	///  
	/// try
	/// {
	///     // Save the changes on the ObjectSet
	///     context.PersistChanges&lt;User&gt;(objectSet);
	///     // Commit the transaction.
	///     context.Commit();
	/// }
	/// catch (ConcurrencyException ex)
	/// {
	///     // We got a concurrency problem. Roll the transaction
	///     // back and notify the user of the program.
	///     context.Rollback();
	///     Console.WriteLine("We got a concurrency problem!");
	/// }
	///     </code>
	/// </example>
	public class ObjectContext : MarshalByRefObject, IDisposable
	{
		private static ObjectContextFactory _factory;

		private WeakReferencesCache<int, object> _instancesCache = new WeakReferencesCache<int, object>();
		private RelationsManager _relationsManager;
		private IStorage _storage;
		private IConcurrencyManager _concurrencyManager;
		private ICacheManager _cacheManager;
		private ObjectPersister _persister;
		private PersistingTrace _persistingTrace = new PersistingTrace();
		private InspectedTrace _inspectedTrace = null;
		private PersistentQueriesProvidersCollection _persistentproviders = new PersistentQueriesProvidersCollection();
		private IdentityMap _identityMap = new IdentityMap();
		private bool _disposed;

		/// <summary>
		/// Creates a new instance of the <see cref="ObjectContext">ObjectContext Class</see>.
		/// </summary>
		/// <example>
		///     The following example shows how to create a new ObjectContext. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///     </code>
		/// </example>
		/// <param name="storage">Instance of the class that represents the physical storage.</param>
		/// <exception cref="ArgumentNullException">Storage is null.</exception>
		public ObjectContext(IStorage storage)
		{
			if (storage == null)
				throw new ArgumentNullException("storage");

			_storage = storage;
			_relationsManager = new RelationsManager(this);
			_persister = new ObjectPersister(this);

			// Register events.
			_persister.Deleting += new EventHandler<ObjectPersistingEventArgs>(persister_Deleting);
			_persister.Inserting += new EventHandler<ObjectPersistingEventArgs>(persister_Inserting);
			_persister.Updating += new EventHandler<ObjectPersistingEventArgs>(persister_Updating);
			_persister.Deleted += new EventHandler<ObjectPersistedEventArgs>(persister_Deleted);
			_persister.Inserted += new EventHandler<ObjectPersistedEventArgs>(persister_Inserted);
			_persister.Updated += new EventHandler<ObjectPersistedEventArgs>(persister_Updated);
		}

		/// <summary>
		/// Destructs a new instance of the <see cref="ObjectContext">ObjectContext Class</see>.
		/// </summary>
		~ObjectContext()
		{
			((IDisposable)this).Dispose();
		}

		/// <summary>
		/// Gets or sets a class implementing the <see cref="IPersistentFactory">IPersistentFactory</see> interface.
		/// </summary>
		/// <remarks>
		/// A class implementing the interface provides instances of persistent objects.
		/// </remarks>
		public static IPersistentFactory PersistentFactory
		{
			get { return ObjectPool.Current.PersistentFactory; }
			set { ObjectPool.Current.PersistentFactory = value; }
		}

		/// <summary>
		/// Gets the <see cref="ObjectContextFactory">ObjectContextFactory</see> that allows creating 
		/// <see cref="ObjectContext">ObjectContext</see> instances by applying a <see cref="ObjectContextFactoryPolicyBase">policy</see>. 
		/// Such as creating a  new <see cref="ObjectContext">ObjectContext</see> instance on each call (ASP.NET applications) or for
		/// each different thread (Windows applications).
		/// </summary>
		/// <example>
		/// This example shows how to set up the factory to create an ObjectContext instance for each new thread.
		/// <code lang="CS">
		/// // Set the policy for multi threading.
		/// ObjectContext.Factory.Policy = new PerThreadObjectContextFactoryPolicy(delegate()
		/// {
		///     MsSqlStorage storage = new MsSqlStorage("... connection string ...");
		///     ObjectContext ctx = new ObjectContext(storage);
		///
		///     return ctx;
		/// });
		/// 
		/// // ... Other code
		/// 
		/// // Have an ObjectContext instance created
		/// ObjectContext context = ObjectContext.Factory.GetObjectContext();
		/// </code>
		/// </example>
		public static ObjectContextFactory Factory
		{
			get 
			{
				if (_factory == null)
					_factory = new ObjectContextFactory();
				return _factory;
			}
		}

		#region ObjectInfo

		/// <summary>
		/// Returns the <see cref="Opf3.ObjectInfo">ObjectInfo</see> object of the given
		/// persistent object. The container holds information about the state of the
		/// object.
		/// </summary>
		/// <returns>
		/// The <see cref="Opf3.ObjectInfo">ObjectInfo</see> object of the given
		/// persistent.
		/// </returns>
		/// <param name="obj">Persistent object that's <see cref="Opf3.ObjectInfo">ObjectInfo</see> object is required.</param>
		/// <exception cref="ArgumentNullException">Obj is null.</exception>
		public ObjectInfo GetObjectInfo(object obj)
		{
			// The object can't be null.
			if (obj == null)
				throw new ArgumentNullException("obj");

			ObjectInfo objectInfo = null;
			// Check if the persistent is implementing the ISelfContainingObject interface.
			ISelfContainingObject selfContainingObject = obj as ISelfContainingObject;
			if (selfContainingObject != null)
				objectInfo = selfContainingObject.ObjectInfo;
			else
				objectInfo = (ObjectInfo)_instancesCache.GetObjectTag(obj.GetHashCode(), obj);

			// If a valid ObjectInfo object has been found return it.
			if (objectInfo != null)
				return objectInfo;

			// Set the ObjectInfo object if null.
			return SetObjectInfo(obj, new ObjectInfo());
		}

		/// <summary>
		/// Sets the <see cref="Opf3.ObjectInfo">ObjectInfo</see> object of the perisistent
		/// object. The container holds information about the state of the persistent object.
		/// </summary>
		/// <param name="obj">
		/// Persistent object that's <see cref="Opf3.ObjectInfo">ObjectInfo</see> object is set.
		/// </param>
		/// <param name="oi">The ObjectInfo object that is set.</param>
		private ObjectInfo SetObjectInfo(object obj, ObjectInfo oi)
		{
			if (oi == null)
				throw new ArgumentNullException("oi");

			ISelfContainingObject selfContainingObject = obj as ISelfContainingObject;
			if (selfContainingObject != null)
			{
				selfContainingObject.ObjectInfo = oi;
			}
			else
			{
				int hash = obj.GetHashCode();

				if (_instancesCache.GetObjectTag(hash, obj) == null)
					_instancesCache.Add(hash, obj, oi);
				else
				{
					// Update the tag if already in the dictinary.
					_instancesCache.UpdateObjectTag(hash, obj, oi);
				}
			}

			return oi;
		}

		#endregion

		/// <summary>
		/// Returns the class that implements the <see cref="Opf3.Storages.IStorage">IStorage</see>
		/// interface.
		/// </summary>
		/// <remarks>
		/// The class returned represents the physical storage that stores the objects on a device.
		/// </remarks>
		/// <value>The class that represents the physical storage.</value>
		public IStorage Storage
		{
			get { return _storage; }
		}

		/// <summary>
		/// Specifies the class that implements the 
		/// <see cref="Opf3.Concurrency.IConcurrencyManager">IConcurrencyManager</see> interface.
		/// </summary>
		/// <remarks>
		/// The <see cref="Opf3.Concurrency.IConcurrencyManager">IConcurrencyManager</see>
		/// checks if somebody else has changed the object in the meantime (in the time it has been
		/// in memory). It throws a
		/// <see cref="Opf3.Concurrency.ConcurrencyException">ConcurrencyException</see> if
		/// somebody else altered the object in the meantime. If the program using the framework is
		/// not the only one working on a storage it is always required to set a
		/// <see cref="Opf3.Concurrency.IConcurrencyManager">IConcurrencyManager</see>.
		/// </remarks>
		/// <example>
		///     The following example shows how to set the Md5ConcurrencyManager. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		/// // Set the ConcurrencyManager.
		/// context.ConcurrencyManager = new Md5ConurrencyManager();
		///     </code>
		/// </example>
		/// <value>
		/// Returns the
		/// <see cref="Opf3.Concurrency.IConcurrencyManager">IConcurrencyManager</see> of the
		/// <see cref="ObjectContext">ObjectContext</see> or null if no manager has been
		/// specified.
		/// </value>
		public IConcurrencyManager ConcurrencyManager
		{
			get { return _concurrencyManager; }
			set 
			{
				if (value == null)
					Tracing.Current.TraceVerbose("ConcurrencyManager has been set to null.");

				_concurrencyManager = value; 
			}
		}

		/// <summary>
		/// Specifies the class that implements the <see cref="Opf3.Caching.ICacheManager">ICacheManager</see>
		/// interface.
		/// </summary>
		/// <remarks>
		/// The <see cref="Opf3.Caching.ICacheManager">ICacheManager</see> holds instances of created persistent
		/// objects as long as they do not expire. If the cache contains still an instance of a persistent object
		/// and the object is to be reloaded the cached instance is re-used.
		/// </remarks>
		/// <example>
		///     The following example shows how to set the SimpleCacheManager. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		/// // Set the CacheManager.
		/// context.CacheManager = new SimpleCacheManager();
		///     </code>
		/// </example>
		/// <value>
		/// Returns the
		/// <see cref="Opf3.Caching.ICacheManager">ICacheManager</see> of the
		/// <see cref="ObjectContext">ObjectContext</see> or null if no manager has been
		/// specified.
		/// </value>
		public ICacheManager CacheManager
		{
			get { return _cacheManager; }
			set 
			{
				if (value == null)
					Tracing.Current.TraceVerbose("CacheManager has been set to null.");

				_cacheManager = value;
			}
		}

		/// <summary>
		/// Returns the <see cref="Opf3.Relations.RelationsManager">RelationsManager</see>
		/// associated with the <see cref="ObjectContext">ObjectContext</see>. This class manages
		/// the relations between persistent objects.
		/// </summary>
		/// <value>
		/// 	<see cref="Opf3.Relations.RelationsManager">RelationsManager</see> created by the
		/// context.
		/// </value>
		internal RelationsManager RelationsManager
		{
			get { return _relationsManager; }
		}

		/// <summary>
		/// Returns the <see cref="Opf3.ObjectPersister">ObjectPersister</see> associated with the 
		/// <see cref="ObjectContext">ObjectContext</see>. This class persists a single persistent object
		/// to the storage.
		/// </summary>
		internal ObjectPersister ObjectPersister
		{
			get { return _persister; }
		}

		/// <summary>
		/// Gets the list of <see cref="IPersistentQueriesProvider">IPersistentQueriesProviders</see>. An
		/// <see cref="IPersistentQueriesProvider">IPersistentQueriesProvider</see> allows to specify the insert,
		/// update and delete query statements directly. The framework is going to use these statements (instead of 
		/// the automatically created ones) when doing inserts, updates and deletes on persistent objects.
		/// </summary>
		public PersistentQueriesProvidersCollection PersistentQueriesProviders
		{
			get { return _persistentproviders; }
		}

		/// <summary>
		/// Gets or sets a value that specifies whether the related objects should be loaded automatically.
		/// </summary>
		/// <remarks>
		/// <para>
		/// This property specifies a value that indicates whether related objects should be loaded automatically when
		/// invoking the Value property of the <see cref="ObjectHolder{T}" />, <see cref="ObjectSetHolder{T}" /> 
		/// or <see cref="ObjectListHolder{T}" />.
		/// </para>
		/// <para>
		/// If the behaviour (default is true) is changed the related objects can only be loaded by using the Load 
		/// method of the object holder objects. After calling the Load method the InnerObject property will hold 
		/// the related objects.
		/// </para>
		/// </remarks>
		public bool AutomaticallyLoadRelatedObjects
		{
			get { return this.RelationsManager.AutomaticallyLoadRelatedObjects; }
			set { this.RelationsManager.AutomaticallyLoadRelatedObjects = value; }
		}

		/// <summary>
		/// Gets or sets whether the objects (and its relations) are serialized for .NET remoting over binary channels. 
		/// If the object is serialized for remoting lazy loading of relations is enabled. Otherwise lazy loading 
		/// is disabled. This option should only get enabled for remoting over binary channels and does not work 
		/// with Windows Communication Foundation or web services in general.
		/// </summary>
		public bool EnableRemotingSerialization
		{
			get { return this.RelationsManager.UseRemotingSerialization; }
			set { this.RelationsManager.UseRemotingSerialization = value; }
		}

		/// <summary>
		/// Gets the <see cref="IdentityMap" /> for the current <see cref="ObjectContext" /> instance.
		/// </summary>
		/// <remarks>
		/// An identity map represents the set of the current loaded persistent objects. Enabling it
		/// means that persistent objects that are found in memory won't get reloaded from the storage. The objects
		/// in memory will be used instead of items that might have come from the storage.
		/// </remarks>
		public IdentityMap IdentityMap
		{
			get { return _identityMap; }
		}

		/// <summary>
		/// Returns a new generic <see cref="Opf3.ObjectSearcher{T}">ObjectSearcher</see>
		/// class.
		/// </summary>
		/// <remarks>
		/// An <see cref="Opf3.ObjectSearcher{T}">ObjectSearcher</see> is used to find items in
		/// the storage, by applying conditions on the
		/// <see cref="Opf3.ObjectSearcher{T}.FindAll()">FindAll</see> routine of the class. By
		/// deriving form <see cref="Opf3.ObjectSearcher{T}">ObjectSearcher</see> and overriding the
		/// <see cref="Opf3.ObjectSearcher{T}.FindAll()">FindAll</see> routines you can implement
		/// your own load mechanism for your persistent objects.
		/// </remarks>
		/// <example>
		///     The following example shows how to get and use an
		///     <see cref="Opf3.ObjectSearcher{T}">ObjectSearcher</see>.
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the ObjectSearcher class for user.
		/// ObjectSearcher&lt;User&gt; searcher = context.GetObjectSearcher&lt;User&gt;();
		/// // Find all user matching the name. The result is sorted by name.
		/// ObjectSet&lt;User&gt; objectSet = searcher.FindAll("Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// foreach(User user in objectSet)
		/// {
		///     // Do something.
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// A generic <see cref="Opf3.ObjectSearcher{T}">ObjectSearcher</see> class that allows
		/// you to search for persistent objects.
		/// </returns>
		public ObjectSearcher<T> GetObjectSearcher<T>()
		{
			return new ObjectSearcher<T>(this);
		}


/*
		/// <summary>
		/// Sets the state of the persistent object to the given <see cref="Opf3.ObjectStates">ObjectStates</see>.
		/// </summary>
		/// <remarks>
		/// 	<para>This routine allows to update an object in the storage without having it
		///     loaded. It's important that all properties that are persisted have the same values
		///     as the fields of the record in the storage. If they vary the
		///     <see cref="Opf3.Concurrency.IConcurrencyManager">IConcurrencyManager</see> will
		///     throw an exception during the next save process.</para>
		/// 	<para>You could use this routine to avoid implementing the
		///     <see cref="ISelfContainingObject">ISelfContainingObject</see> interface when
		///     loading a persistent object with one <see cref="ObjectContext">ObjectContext</see>
		///     and saving it with another (that works on the same storage).</para>
		/// </remarks>
		/// <example>
		///     The following example changes the state of an object. 
		///     <code lang="CS">
		/// // Load the object from the storage.
		///  User user1 = context.GetObject&lt;User&gt;("Id = {0}", "1");
		///  
		///  // Create a new user object.
		///  User user2 = new User();
		///  // Copy all properties of the first user object to the second.
		///  user2.Name = user1.Name;
		///  // ... Other properties.
		///  
		///  // Set the state of the object as inserted. This means that
		///  // the framework will do an update the next time when saving the 
		///  // object.
		///  context.SetObjectState&lt;User&gt;(user2, ObjectStates.Inserted);
		///  
		///  // Change the object.
		///  user2.Name = "new Name";
		///  // Persist the changes.
		///  context.PersistChanges(user2);
		///     </code>
		/// </example>
		/// <param name="obj">
		/// Persistent objects that <see cref="Opf3.ObjectStates">ObjectStates</see> is changed.
		/// </param>
		/// <param name="objectState">
		/// 	<see cref="Opf3.ObjectStates">ObjectStates</see> that is set for the given
		/// persistent object.
		/// </param>
		[Obsolete("Please use MarkForDeletion or implement ISelfContainingObject if you need to change the state manually.", true)]
		public bool SetObjectState(object obj, ObjectStates objectState)
		{
			return false;
		}
*/

		/// <summary>
		/// Attaches the persistent object and the related objects to the <see cref="ObjectContext" />.
		/// </summary>
		/// <param name="persistent">The persistent object whose related objects are 
		/// attached to the <see cref="ObjectContext" />.</param>
		public void Attach(object persistent)
		{
			if (persistent == null)
				throw new ArgumentNullException("persistent");

			// connect the related objects to the ObjectContext instance.
			_relationsManager.ConnectRelated(persistent);
		}

		#region IsModified

		/// <summary>
		/// Returns whether the object has been modified since the last operation.
		/// </summary>
		/// <remarks>
		/// Validates the data of the object set as argument and returns whether the object has been
		/// modified since the last operation. The last operation is the last insert, load, update on the
		/// object.
		/// </remarks>
		/// <example>
		///     The following example shows how to use this method.
		///     <code lang="CS">
		///  // Load the object from the storage.
		///  User user = context.GetObject&lt;User&gt;("Id = {0}", "1");
		///  
		///  // Set a new name for the user object.
		///  user.Name = "new Name";
		///  
		///  // Check if the object has been modified.
		///  if (context.IsModified&lt;User&gt;(user))
		///      Console.WriteLine("Object has been changed.");
		///  
		///     </code>
		/// </example>
		/// <param name="obj">
		/// Persistent objects that is checked for being modified.
		/// </param>
		/// <exception cref="ArgumentNullException">Obj is null.</exception>
		public bool IsModified(object obj)
		{
			return IsModified(obj, false);
		}

		/// <summary>
		/// Returns whether the object (and its related objects) has been modified since the last operation.
		/// </summary>
		/// <remarks>
		/// Validates the data of the object set as argument and returns whether the object (plus eventually 
		/// the full loaded object graph) has been modified since the last operation. The last operation is 
		/// the last insert, load, update on the object.
		/// </remarks>
		/// <example>
		///     The following example shows how to use this method.
		///     <code lang="CS">
		///  // Load the object from the storage.
		///  User user = context.GetObject&lt;User&gt;("Id = {0}", "1");
		///  
		///  // Set a new name for the user object.
		///  user.Name = "new Name";
		///  
		///  // Check if the object has been modified.
		///  if (context.IsModified&lt;User&gt;(user))
		///      Console.WriteLine("Object has been changed.");
		///  
		///     </code>
		/// </example>
		/// <param name="obj">Persistent objects that is checked for being modified.</param>
		/// <param name="checkFullLoadedGraph">True to check all objects in the loaded object graph for being modified.</param>
		/// <exception cref="ArgumentNullException">Obj is null.</exception>
		public bool IsModified(object obj, bool checkFullLoadedGraph)
		{
			if (obj == null)
				throw new ArgumentNullException("obj");

			bool entryPoint = (_inspectedTrace == null);

			try
			{
				// if this is not the entry point and the object is already in the trace
				// we can savely return false. It has been checked already and if the check
				// would have resulted in a true we wouldn't be here because a check resulting
				// in true immediately returns.
				if (!entryPoint && _inspectedTrace.Contains(obj))
					return false;

				// get the object info object.
				ObjectInfo info = GetObjectInfo(obj);
				// return true when the object hasn't been saved or has been recently deleted.
				if (info.ObjectState == ObjectStates.None || info.ObjectState == ObjectStates.Deleted)
					return true;

				// check whether the new checksum equals with the current.
				bool modified = !ChecksumBuilder.EqualsChecksum(info.Checksum, ChecksumBuilder.CalculatePersistentChecksum(obj));
				if (modified)
					return true;

				// return the value if only the first level should be inspected.
				if (!checkFullLoadedGraph)
					return modified;

				// create a new instance of the inspected graph.
				if (entryPoint)
					_inspectedTrace = new InspectedTrace();

				// add the current object to the inspected trace.
				_inspectedTrace.Add(obj);
				// check the related objects for being modified.
				return this.RelationsManager.IsRelatedModified(obj);
			}
			finally
			{
				if (entryPoint)
					_inspectedTrace = null;
			}
		}

		#endregion

		#region GetObjectReader

		/// <summary>
		/// Creates and executes an <see cref="Opf3.ObjectReader{T}">ObjectReader</see> on
		/// the <see cref="ObjectContext">ObjectContext</see>.
		/// </summary>
		/// <remarks>
		/// This routine returns an <see cref="Opf3.ObjectReader{T}">ObjectReader</see> that
		/// is a forward-only cursor through the resultset. The
		/// <see cref="Opf3.ObjectReader{T}">ObjectReader</see> allows you to go through the
		/// resultset object per object. Usually an
		/// <see cref="Opf3.ObjectReader{T}">ObjectReader</see> is used in export or batch routines
		/// to minimize the memory amount.
		/// </remarks>
		/// <example>
		///     The following example introduces the use of the GetObjectReader routine.
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Gets all object matching the name and sorting them by name.
		/// // Returns the objects in an ObjectReader.
		/// ObjectReader&lt;User&gt; reader = context.GetObjectReader&lt;User&gt;();
		///  
		/// while(reader.Read())
		/// {
		///     User user = reader.Current;
		///     // Do something.
		/// }
		///  
		/// // ObjectReader supports also foreach
		/// // foreach(User user in reader)
		/// // {
		/// //       // Do something.
		/// // }
		///     </code>
		/// </example>
		/// <returns>
		/// An <see cref="Opf3.ObjectReader{T}">ObjectReader</see> representing a
		/// forward-only cursor on the resultset.
		/// </returns>
		public virtual ObjectReader<T> GetObjectReader<T>()
		{
			return this.GetObjectReader<T>(new ObjectQuery<T>());
		}

		/// <summary>
		/// Creates and executes an <see cref="Opf3.ObjectReader{T}">ObjectReader</see> on
		/// the <see cref="ObjectContext">ObjectContext</see>.
		/// </summary>
		/// <remarks>
		/// This routine returns an <see cref="Opf3.ObjectReader{T}">ObjectReader</see> that can 
		/// be seen as forward-only cursor through the resultset. The 
		/// <see cref="Opf3.ObjectReader{T}">ObjectReader</see> allows you to go through the resultset
		/// object per object. Usually an <see cref="Opf3.ObjectReader{T}">ObjectReader</see> is used
		/// in export or batch routines to minimize the memory amount.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectReader routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Gets all object matching the name and sorting them by name.
		/// // Returns the objects in an ObjectReader.
		/// ObjectReader&lt;User&gt; reader = context.GetObjectReader&lt;User&gt;
		///     ("Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// while(reader.Read())
		/// {
		///     User user = reader.Current;
		///     // Do something.
		/// }
		///  
		/// // ObjectReader supports also foreach
		/// // foreach(User user in reader)
		/// // {
		/// //       // Do something.
		/// // }
		///     </code>
		/// </example>
		/// <returns>
		/// An <see cref="Opf3.ObjectReader{T}">ObjectReader</see> representing a
		/// forward-only cursor on the resultset.
		/// </returns>
		/// <param name="query">
		/// An instance of a class that implements the
		/// <see cref="Opf3.Query.IQuery">IQuery</see> interface. This query is compiled and used
		/// to retrieve the objects from the storage.
		/// </param>
		public virtual ObjectReader<T> GetObjectReader<T>(IQuery query)
		{
			return this.GetObjectReader<T>(query, false);
		}

		/// <summary>
		/// Creates and executes an <see cref="Opf3.ObjectReader{T}">ObjectReader</see> on
		/// the <see cref="ObjectContext">ObjectContext</see>.
		/// </summary>
		/// <remarks>
		/// This routine returns an <see cref="Opf3.ObjectReader{T}">ObjectReader</see> that can 
		/// be seen as forward-only cursor through the resultset. The 
		/// <see cref="Opf3.ObjectReader{T}">ObjectReader</see> allows you to go through the resultset
		/// object per object. Usually an <see cref="Opf3.ObjectReader{T}">ObjectReader</see> is used
		/// in export or batch routines to minimize the memory amount.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectReader routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Gets all object matching the name and sorting them by name.
		/// // Returns the objects in an ObjectReader.
		/// ObjectReader&lt;User&gt; reader = context.GetObjectReader&lt;User&gt;
		///     ("Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// while(reader.Read())
		/// {
		///     User user = reader.Current;
		///     // Do something.
		/// }
		///  
		/// // ObjectReader supports also foreach
		/// // foreach(User user in reader)
		/// // {
		/// //       // Do something.
		/// // }
		///     </code>
		/// </example>
		/// <returns>
		/// An <see cref="Opf3.ObjectReader{T}">ObjectReader</see> representing a
		/// forward-only cursor on the resultset.
		/// </returns>
		/// <param name="query">
		/// An instance of a class that implements the
		/// <see cref="Opf3.Query.IQuery">IQuery</see> interface. This query is compiled and used
		/// to retrieve the objects from the storage.
		/// </param>
		/// <param name="ignoreCache">True to ignore the cache set.</param>
		internal ObjectReader<T> GetObjectReader<T>(IQuery query, bool ignoreCache)
		{
			// Check if a cache manager is installed.
			if (this.CacheManager != null && !ignoreCache)
				return this.CacheManager.GetObjectReader<T>(this, query);

			// Get the ObjectReader instance.
			ObjectReader<T> reader = _storage.ExecuteReader<T>(this, query);
			// Subscribe to the loaded and loading event.
			reader.Loaded += new EventHandler<ObjectLoadedEventArgs>(reader_Loaded);
			reader.Loading += new EventHandler<ObjectLoadingEventArgs>(reader_Loading);

			return reader;
		}

		/// <summary>
		/// Creates and executes an <see cref="Opf3.ObjectReader{T}">ObjectReader</see> on
		/// the <see cref="ObjectContext">ObjectContext</see>.
		/// </summary>
		/// <remarks>
		/// This routine returns an <see cref="Opf3.ObjectReader{T}">ObjectReader</see> that
		/// is a forward-only cursor through the resultset. The
		/// <see cref="Opf3.ObjectReader{T}">ObjectReader</see> allows you to go through the
		/// resultset object per object. Usually an
		/// <see cref="Opf3.ObjectReader{T}">ObjectReader</see> is used in export or batch routines
		/// to minimize the memory amount.
		/// </remarks>
		/// <example>
		///     The following example introduces the use of the GetObjectReader routine.
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Gets all object matching the name and sorting them by name.
		/// // Returns the objects in an ObjectReader.
		/// ObjectReader&lt;User&gt; reader = context.GetObjectReader&lt;User&gt;
		///     ("Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// while(reader.Read())
		/// {
		///     User user = reader.Current;
		///     // Do something.
		/// }
		///  
		/// // ObjectReader supports also foreach
		/// // foreach(User user in reader)
		/// // {
		/// //       // Do something.
		/// // }
		///     </code>
		/// </example>
		/// <returns>
		/// An <see cref="Opf3.ObjectReader{T}">ObjectReader</see> representing a
		/// forward-only cursor on the resultset.
		/// </returns>
		/// <param name="conditions">A condition string that specifies the objects that are loaded.</param>
		/// <param name="parameter">A list of parameter that is passed as parameter for the conditions.</param>
		public virtual ObjectReader<T> GetObjectReader<T>(string conditions, params object[] parameter)
		{
			return this.GetObjectReader<T>(new ObjectQuery<T>(conditions, parameter));
		}

		#endregion

		#region GetObjectList

		/// <summary>
		/// Fills an instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface with all objects (found in the storage) of the given type.
		/// </summary>
		/// <remarks>
		/// Returns a filled list of objects. All kind of lists that implement
		/// the <see cref="System.Collections.Generic.IList{T}">IList</see> interface are allowed.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectList routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Gets all object matching the name and sorting them by name.
		/// IList&lt;User%gt; userList = null;
		/// userList = context.GetObjectReader&lt;User&gt;(new List&lt;User&gt;());
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in userList)
		/// {
		///     // Do something.
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// The instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface.
		/// </returns>
		/// <param name="list">An instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface.</param>
		public virtual IList<T> GetObjectList<T>(IList<T> list)
		{
			return GetObjectList<T>(list, new ObjectQuery<T>());
		}

		/// <summary>
		/// Fills an instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface with objects.
		/// </summary>
		/// <remarks>
		/// Returns a filled list of objects. All kind of lists that implement
		/// the <see cref="System.Collections.Generic.IList{T}">IList</see> interface are allowed.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectList routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Gets all object matching the name and sorting them by name.
		/// IList&lt;User%gt; userList = null;
		/// userList = context.GetObjectReader&lt;User&gt;(new List&lt;User&gt;(), 
		///		"Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in userList)
		/// {
		///     // Do something.
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// The instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface.
		/// </returns>
		/// <param name="list">An instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface.</param>
		/// <param name="conditions">A condition string that specifies the objects that are loaded.</param>
		/// <param name="parameter">A list of parameter that is passed as parameter for the conditions.</param>
		public virtual IList<T> GetObjectList<T>(IList<T> list, string conditions, params object[] parameter)
		{
			return GetObjectList<T>(list, new ObjectQuery<T>(conditions, parameter));
		}

		/// <summary>
		/// Fills an instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface with objects.
		/// </summary>
		/// <remarks>
		/// Returns a filled list of objects. All kind of lists that implement
		/// the <see cref="System.Collections.Generic.IList{T}">IList</see> interface are allowed.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectList routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Gets all object matching the name and sorting them by name.
		/// IList&lt;User%gt; userList = null;
		/// userList = context.GetObjectReader&lt;User&gt;(new List&lt;User&gt;(), 
		///		new ObjectQuery&lt;User&gt;("Name like {0} SortBy Name Asc", "%mith%"));
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in userList)
		/// {
		///     // Do something.
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// The instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface.
		/// </returns>
		/// <param name="list">An instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface.</param>
		/// <param name="query">
		/// An instance of a class that implements the
		/// <see cref="Opf3.Query.IQuery">IQuery</see> interface. This query is compiled and used
		/// to retrieve the objects from the storage.
		/// </param>
		/// <exception cref="ArgumentNullException">List is null.</exception>
		public virtual IList<T> GetObjectList<T>(IList<T> list, IQuery query)
		{
			return GetObjectList<T>(list, query, -1);
		}

		/// <summary>
		/// Fills an instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface with objects.
		/// </summary>
		/// <remarks>
		/// Returns a filled list of objects. All kind of lists that implement
		/// the <see cref="System.Collections.Generic.IList{T}">IList</see> interface are allowed.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectList routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Gets all object matching the name and sorting them by name.
		/// IList&lt;User%gt; userList = null;
		/// userList = context.GetObjectReader&lt;User&gt;(new List&lt;User&gt;(), 
		///		new ObjectQuery&lt;User&gt;("Name like {0} SortBy Name Asc", "%mith%"), 10);
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in userList)
		/// {
		///     // Do something.
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// The instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface.
		/// </returns>
		/// <param name="list">An instance of a class that implements the <see cref="System.Collections.Generic.IList{T}">IList</see>
		/// interface.</param>
		/// <param name="query">
		/// An instance of a class that implements the
		/// <see cref="Opf3.Query.IQuery">IQuery</see> interface. This query is compiled and used
		/// to retrieve the objects from the storage.
		/// </param>
		/// <param name="amount">Amount of objects that are loaded from the storage. This allows you
		/// to load only the first, for example, 10 objects.</param>
		/// <exception cref="ArgumentNullException">List is null.</exception>
		public virtual IList<T> GetObjectList<T>(IList<T> list, IQuery query, int amount)
		{
			if (list == null)
				throw new ArgumentNullException("list");

			ICustomPersister customPersister = list as ICustomPersister;
			if (customPersister != null)
			{
				if (amount <= -1)
					customPersister.Load(this, query);
				else
					customPersister.Load(this, query, amount);
			}
			else
			{
				using (ObjectReader<T> reader = this.GetObjectReader<T>(query))
				{
					// Add new items until we reached the max. amount or the ObjecrReader does not return more items.
					int current = 0;
					while (reader.MoveNext() && (amount == -1 || current < amount))
					{
						list.Add(reader.Current);
						current++;
					}
				}
			}
			return list;
		}

		#endregion

		#region GetObjectSet

		/// <summary>
		/// Fills an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> with all the objects of the given type.
		/// </summary>
		/// <remarks>
		/// Returns a filled <see cref="Opf3.ObjectSet{T}">ObjectSet</see>. An 
		/// <see cref="Opf3.ObjectSet{T}">ObjectSet</see> is as a in memory cache for objects. Use the
		/// conditions to restrict the result of the routine.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectSet routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the ObjectSet with user matching the name and sorting them by name.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;();
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in objectSet)
		/// {
		///     // Do something.
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// An instance of an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> filled with the objects from the storage.
		/// </returns>
		public virtual ObjectSet<T> GetObjectSet<T>()
		{
			return GetObjectSet<T>(new ObjectQuery<T>());
		}

		/// <summary>
		/// Fills an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> with objects.
		/// </summary>
		/// <remarks>
		/// Returns a filled <see cref="Opf3.ObjectSet{T}">ObjectSet</see>. An 
		/// <see cref="Opf3.ObjectSet{T}">ObjectSet</see> is as a in memory cache for objects. Use the
		/// conditions to restrict the result of the routine.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectSet routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the ObjectSet with user matching the name and sorting them by name.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;
		///     ("Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in objectSet)
		/// {
		///     // Do something.
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// An instance of an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> filled with the objects from the storage.
		/// </returns>
		/// <param name="conditions">A condition string that specifies the objects that are loaded.</param>
		/// <param name="parameter">A list of parameter that is passed as parameter for the conditions.</param>
		public virtual ObjectSet<T> GetObjectSet<T>(string conditions, params object[] parameter)
		{
			return GetObjectSet<T>(new ObjectQuery<T>(conditions, parameter));
		}

		/// <summary>
		/// Fills an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> with objects.
		/// </summary>
		/// <remarks>
		/// Returns a filled <see cref="Opf3.ObjectSet{T}">ObjectSet</see>. An 
		/// <see cref="Opf3.ObjectSet{T}">ObjectSet</see> is as a in memory cache for objects.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectSet routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the ObjectSet with user matching the name and sorting them by name.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;
		///     (new ObjectQuery&lt;User&gt;("Name like {0} SortBy Name Asc", "%mith%"));
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in objectSet)
		/// {
		///     // Do something.
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// An instance of an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> filled with the objects from the storage.
		/// </returns>
		/// <param name="query">
		/// An instance of a class that implements the
		/// <see cref="Opf3.Query.IQuery">IQuery</see> interface. This query is compiled and used
		/// to retrieve the objects from the storage.
		/// </param>
		public virtual ObjectSet<T> GetObjectSet<T>(IQuery query)
		{
			if (query == null)
				throw new ArgumentNullException("query");

			ObjectSet<T> os = new ObjectSet<T>();
			// Have the ObjectSet load itself.
			((ICustomPersister)os).Load(this, query);
			return os;
		}

		/// <summary>
		/// Fills an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> with objects.
		/// </summary>
		/// <remarks>
		/// Returns a filled <see cref="Opf3.ObjectSet{T}">ObjectSet</see>. An 
		/// <see cref="Opf3.ObjectSet{T}">ObjectSet</see> is as a in memory cache for objects.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectSet routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the ObjectSet for user.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;
		///     (new ObjectQuery&lt;User&gt;("Name like {0}", "%mith%"), 10);
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in objectSet)
		/// {
		///     // Do something.
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// An instance of an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> filled with the objects from the storage.
		/// </returns>
		/// <param name="query">
		/// An instance of a class that implements the
		/// <see cref="Opf3.Query.IQuery">IQuery</see> interface. This query is compiled and used
		/// to retrieve the objects from the storage.
		/// </param>
		/// <param name="amount">Amount of objects that are loaded from the storage. This allows you
		/// to load only the first, for example, 10 objects.</param>
		public virtual ObjectSet<T> GetObjectSet<T>(IQuery query, int amount)
		{
			if (query == null)
				throw new ArgumentNullException("query");

			ObjectSet<T> os = new ObjectSet<T>();
			// Have the ObjectSet load itself.
			((ICustomPersister)os).Load(this, query, amount);
			return os;
		}

		/// <summary>
		/// Fills an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> with all the objects of the given type.
		/// </summary>
		/// <remarks>
		/// Returns a filled <see cref="Opf3.ObjectSet{T}">ObjectSet</see>. An 
		/// <see cref="Opf3.ObjectSet{T}">ObjectSet</see> is as a in memory cache for objects. Use the
		/// conditions to restrict the result of the routine.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectSet routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the ObjectSet with user matching the name and sorting them by name.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;(
		///		new PersistentTypeSelector(MySelection));
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in objectSet)
		/// {
		///     // Do something.
		/// }
		/// 
		/// // ...
		/// 
		/// private void MySelection(object sender, FetchingStorageRecordEventArgs e)
		/// {
		///     if (e.DataRecord["Type"] == "1")
		///     {
		///         // Switch the type of the persistent that is created to User1.
		///	        e.Type = typeof(User1);
		///     }
		///     // Have a persistent of type User created.
		///     e.Type = typeof(User);
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// An instance of an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> filled with the objects from the storage.
		/// </returns>
		/// <param name="typeSelector">Delegate invoked before each creating of a persistent object. This allows
		/// to dynamically change the type of the created persistent object or ignore some objects.</param>
		public virtual ObjectSet<T> GetObjectSet<T>(PersistentTypeSelector typeSelector)
		{
			return GetObjectSet<T>(typeSelector, new ObjectQuery<T>());
		}

		/// <summary>
		/// Fills an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> with objects.
		/// </summary>
		/// <remarks>
		/// Returns a filled <see cref="Opf3.ObjectSet{T}">ObjectSet</see>. An 
		/// <see cref="Opf3.ObjectSet{T}">ObjectSet</see> is as a in memory cache for objects. Use the
		/// conditions to restrict the result of the routine.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectSet routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the ObjectSet with user matching the name and sorting them by name.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;
		///     (new PersistentTypeSelector(MySelection), "Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in objectSet)
		/// {
		///     // Do something.
		/// }
		/// 
		/// // ...
		/// 
		/// private void MySelection(object sender, FetchingStorageRecordEventArgs e)
		/// {
		///     if (e.DataRecord["Type"] == "1")
		///     {
		///         // Switch the type of the persistent that is created to User1.
		///	        e.Type = typeof(User1);
		///     }
		///     // Have a persistent of type User created.
		///     e.Type = typeof(User);
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// An instance of an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> filled with the objects from the storage.
		/// </returns>
		/// <param name="conditions">A condition string that specifies the objects that are loaded.</param>
		/// <param name="parameter">A list of parameter that is passed as parameter for the conditions.</param>
		/// <param name="typeSelector">Delegate invoked before each creating of a persistent object. This allows
		/// to dynamically change the type of the created persistent object or ignore some objects.</param>
		public virtual ObjectSet<T> GetObjectSet<T>(PersistentTypeSelector typeSelector, string conditions,
			params object[] parameter)
		{
			return GetObjectSet<T>(typeSelector, new ObjectQuery<T>(conditions, parameter));
		}

		/// <summary>
		/// Fills an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> with objects.
		/// </summary>
		/// <remarks>
		/// Returns a filled <see cref="Opf3.ObjectSet{T}">ObjectSet</see>. An 
		/// <see cref="Opf3.ObjectSet{T}">ObjectSet</see> is as a in memory cache for objects.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectSet routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the ObjectSet with user matching the name and sorting them by name.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;
		///     (new PersistentTypeSelector(MySelection), 
		///      new ObjectQuery&lt;User&gt;("Name like {0} SortBy Name Asc", "%mith%"));
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in objectSet)
		/// {
		///     // Do something.
		/// }
		/// 
		/// // ...
		/// 
		/// private void MySelection(object sender, FetchingStorageRecordEventArgs e)
		/// {
		///     if (e.DataRecord["Type"] == "1")
		///     {
		///         // Switch the type of the persistent that is created to User1.
		///	        e.Type = typeof(User1);
		///     }
		///     // Have a persistent of type User created.
		///     e.Type = typeof(User);
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// An instance of an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> filled with the objects from the storage.
		/// </returns>
		/// <param name="query">
		/// An instance of a class that implements the
		/// <see cref="Opf3.Query.IQuery">IQuery</see> interface. This query is compiled and used
		/// to retrieve the objects from the storage.
		/// </param>
		/// <param name="typeSelector">Delegate invoked before each creating of a persistent object. This allows
		/// to dynamically change the type of the created persistent object or ignore some objects.</param>
		public virtual ObjectSet<T> GetObjectSet<T>(PersistentTypeSelector typeSelector, IQuery query)
		{
			if (typeSelector == null)
				throw new ArgumentNullException("typeSelector");
			if (query == null)
				throw new ArgumentNullException("query");

			ObjectSet<T> os = new ObjectSet<T>();
			// Register the PersistentTypeSelector as event target.
			os.FetchingStorageRecord += typeSelector;
			// Have the ObjectSet load itself.
			((ICustomPersister)os).Load(this, query);
			// Unregister the PersistentTypeSelector.
			os.FetchingStorageRecord -= typeSelector;
			return os;
		}

		/// <summary>
		/// Fills an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> with objects.
		/// </summary>
		/// <remarks>
		/// Returns a filled <see cref="Opf3.ObjectSet{T}">ObjectSet</see>. An 
		/// <see cref="Opf3.ObjectSet{T}">ObjectSet</see> is as a in memory cache for objects.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObjectSet routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the ObjectSet for user.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;
		///     (new PersistentTypeSelector(MySelection), 
		///      new ObjectQuery&lt;User&gt;("Name like {0}", "%mith%"), 10);
		///  
		/// // Loop through all items and do something.
		/// foreach(User user in objectSet)
		/// {
		///     // Do something.
		/// }
		/// 
		/// // ...
		/// 
		/// private void MySelection(object sender, FetchingStorageRecordEventArgs e)
		/// {
		///     if (e.DataRecord["Type"] == "1")
		///     {
		///         // Switch the type of the persistent that is created to User1.
		///	        e.Type = typeof(User1);
		///     }
		///     // Have a persistent of type User created.
		///     e.Type = typeof(User);
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// An instance of an <see cref="Opf3.ObjectSet{T}">ObjectSet</see> filled with the objects from the storage.
		/// </returns>
		/// <param name="query">
		/// An instance of a class that implements the
		/// <see cref="Opf3.Query.IQuery">IQuery</see> interface. This query is compiled and used
		/// to retrieve the objects from the storage.
		/// </param>
		/// <param name="amount">Amount of objects that are loaded from the storage. This allows you
		/// to load only the first, for example, 10 objects.</param>
		/// <param name="typeSelector">Delegate invoked before each creating of a persistent object. This allows
		/// to dynamically change the type of the created persistent object or ignore some objects.</param>
		public virtual ObjectSet<T> GetObjectSet<T>(PersistentTypeSelector typeSelector, IQuery query, int amount)
		{
			if (typeSelector == null)
				throw new ArgumentNullException("typeSelector");
			if (query == null)
				throw new ArgumentNullException("query");

			ObjectSet<T> os = new ObjectSet<T>();
			// Register the PersistentTypeSelector as event target.
			os.FetchingStorageRecord += typeSelector;
			// Have the ObjectSet load itself.
			((ICustomPersister)os).Load(this, query, amount);
			// Unregister the PersistentTypeSelector.
			os.FetchingStorageRecord -= typeSelector;
			return os;
		}

		#endregion

		#region GetObject

		/// <summary>
		/// Fetches the first object matching the conditions and returns it.
		/// </summary>
		/// <remarks>
		/// Executes a query on the storage and returns the first object that matches the query. 
		/// If no object is found Null is returned.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObject routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the first user matching the name and sorts them by name.
		/// User user = context.GetObject&lt;User&gt;("Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// // If the user object is null nothing that matches has been found.
		/// if (user == null)
		///     Debug.WriteLine("No object found!");
		/// else
		///     Debug.WriteLine(
		///         string.Format("Object with name {0} has been found.", 
		///         user.Name));
		///     </code>
		/// </example>
		/// <returns>
		/// The first object matching the conditions.
		/// </returns>
		/// <param name="conditions">A condition string that specifies the object that is loaded.</param>
		/// <param name="parameters">A list of parameter that is passed as parameter for the conditions.</param>
		public virtual T GetObject<T>(string conditions, params object[] parameters)
		{
			return GetObject<T>(new ObjectQuery<T>(conditions, parameters));
		}

		/// <summary>
		/// Fetches the first object matching the conditions and returns it.
		/// </summary>
		/// <remarks>
		/// Executes a query on the storage and returns the first object that matches the query. 
		/// If no object is found Null is returned.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObject routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the first user matching the name and sorts them by name.
		/// User user = context.GetObject&lt;User&gt;("Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// // If the user object is null nothing that matches has been found.
		/// if (user == null)
		///     Debug.WriteLine("No object found!");
		/// else
		///     Debug.WriteLine(
		///         string.Format("Object with name {0} has been found.", 
		///         user.Name));
		///     </code>
		/// </example>
		/// <returns>
		/// The first object matching the <see cref="Opf3.Query.IQuery">IQuery</see>.
		/// </returns>
		/// <param name="query">
		/// An instance of a class that implements the
		/// <see cref="Opf3.Query.IQuery">IQuery</see> interface. This query is compiled and used
		/// to retrieve the object from the storage.
		/// </param>
		public virtual T GetObject<T>(IQuery query)
		{
			using (ObjectReader<T> objectReader = this.GetObjectReader<T>(query))
			{
				if (!objectReader.Read())
				{
					Tracing.Current.TraceStorageIO("No object found to load.");
					return default(T);
				}
				return objectReader.Current;
			}
		}

		/// <summary>
		/// Populates a class implementing the <see cref="ICustomPersister">ICustomPersister</see> interface with data.
		/// </summary>
		/// <remarks>
		/// Populates the class implementing the <see cref="ICustomPersister">ICustomPersister</see> with data
		/// from the storage. The class gets the control on how to load the objects from the storage. A query
		/// is also given to have the object loaded the objects matching the query. There is no guarantuee that
		/// the object loads exactly the objects returned by the query, since it controls the loading process
		/// by itself.
		/// </remarks>
		/// <example>
		/// The following example introduces to the use of the GetObject routine 
		/// with the ICustomPersister interface. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Populates the given ObjectSet with data.
		/// ObjectSet&lt;User&gt; = context.GetObject&lt;User&gt;(new ObjectSet&lt;User&gt;(), 
		///		"Name like {0} SortBy Name Asc", "%mith%");
		///     </code>
		/// </example>
		/// <returns>
		/// The first object implementing the <see cref="ICustomPersister">ICustomPersister</see> interface.
		/// </returns>
		/// <param name="customPersister">The class implementing the <see cref="ICustomPersister">ICustomPersister</see>
		/// interface.</param>
		/// <param name="conditions">A condition string that specifies the object that is loaded.</param>
		/// <param name="parameters">A list of parameter that is passed as parameter for the conditions.</param>
		public virtual ICustomPersister GetObject<T>(ICustomPersister customPersister, string conditions, params object[] parameters)
		{
			return GetObject<T>(customPersister, new ObjectQuery<T>(conditions, parameters));
		}

		/// <summary>
		/// Populates a class implementing the <see cref="ICustomPersister">ICustomPersister</see> interface with data.
		/// </summary>
		/// <remarks>
		/// Populates the class implementing the <see cref="ICustomPersister">ICustomPersister</see> with data
		/// from the storage. The class gets the control on how to load the objects from the storage. A query
		/// is also given to have the object loaded the objects matching the query. There is no guarantuee that
		/// the object loads exactly the objects returned by the query, since it controls the loading process
		/// by itself.
		/// </remarks>
		/// <example>
		/// The following example introduces to the use of the GetObject routine 
		/// with the ICustomPersister interface. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Populates the given ObjectSet with data.
		/// ObjectSet&lt;User&gt; = context.GetObject&lt;User&gt;(new ObjectSet&lt;User&gt;(), 
		///		"Name like {0} SortBy Name Asc", "%mith%");
		///     </code>
		/// </example>
		/// <returns>
		/// The first object implementing the <see cref="ICustomPersister">ICustomPersister</see> interface.
		/// </returns>
		/// <param name="query">
		/// An instance of a class that implements the
		/// <see cref="Opf3.Query.IQuery">IQuery</see> interface. This query is compiled and used
		/// to retrieve the object from the storage.
		/// </param>
		/// <param name="customPersister">The class implementing the <see cref="ICustomPersister">ICustomPersister</see>
		/// interface.</param>
		public virtual ICustomPersister GetObject<T>(ICustomPersister customPersister, IQuery query)
		{
			if (customPersister == null)
				throw new ArgumentNullException("customPersister");
			if (query == null)
				throw new ArgumentNullException("query");

			customPersister.Load(this, query);
			return customPersister;
		}

		/// <summary>
		/// Fetches the first object matching the conditions and returns it.
		/// </summary>
		/// <remarks>
		/// Executes a query on the storage and returns the first object that matches the query. 
		/// If no object is found Null is returned.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObject routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the first user matching the name and sorts them by name.
		/// User user = context.GetObject&lt;User&gt;(new PersistentTypeSelector(MySelection),
		///     "Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// // If the user object is null nothing that matches has been found.
		/// if (user == null)
		///     Debug.WriteLine("No object found!");
		/// else
		///     Debug.WriteLine(
		///         string.Format("Object with name {0} has been found.", 
		///         user.Name));
		/// 
		/// // ...
		/// 
		/// private void MySelection(object sender, FetchingStorageRecordEventArgs e)
		/// {
		///     if (e.DataRecord["Type"] == "1")
		///     {
		///         // Switch the type of the persistent that is created to User1.
		///	        e.Type = typeof(User1);
		///     }
		///     // Have a persistent of type User created.
		///     e.Type = typeof(User);
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// The first object matching the conditions.
		/// </returns>
		/// <param name="typeSelector">Delegate invoked before each creating of a persistent object. This allows
		/// to dynamically change the type of the created persistent object or ignore some objects.</param>
		/// <param name="conditions">A condition string that specifies the object that is loaded.</param>
		/// <param name="parameters">A list of parameter that is passed as parameter for the conditions.</param>
		public virtual T GetObject<T>(PersistentTypeSelector typeSelector, string conditions, params object[] parameters)
		{
			return GetObject<T>(typeSelector, new ObjectQuery<T>(conditions, parameters));
		}

		/// <summary>
		/// Fetches the first object matching the conditions and returns it.
		/// </summary>
		/// <remarks>
		/// Executes a query on the storage and returns the first object that matches the query. 
		/// If no object is found Null is returned.
		/// </remarks>
		/// <example>
		///     The following example introduces to the use of the GetObject routine. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the first user matching the name and sorts them by name.
		/// User user = context.GetObject&lt;User&gt;(new PersistentTypeSelector(MySelection),
		///     new ObjectQuery&lt;User&gt;("Name like {0} SortBy Name Asc", "%mith%"));
		///  
		/// // If the user object is null nothing that matches has been found.
		/// if (user == null)
		///     Debug.WriteLine("No object found!");
		/// else
		///     Debug.WriteLine(
		///         string.Format("Object with name {0} has been found.", 
		///         user.Name));
		/// 
		/// // ...
		/// 
		/// private void MySelection(object sender, FetchingStorageRecordEventArgs e)
		/// {
		///     if (e.DataRecord["Type"] == "1")
		///     {
		///         // Switch the type of the persistent that is created to User1.
		///	        e.Type = typeof(User1);
		///     }
		///     // Have a persistent of type User created.
		///     e.Type = typeof(User);
		/// }
		///     </code>
		/// </example>
		/// <returns>
		/// The first object matching the <see cref="Opf3.Query.IQuery">IQuery</see>.
		/// </returns>
		/// <param name="typeSelector">Delegate invoked before each creating of a persistent object. This allows
		/// to dynamically change the type of the created persistent object or ignore some objects.</param>
		/// <param name="query">An instance of a class that implements the
		/// <see cref="Opf3.Query.IQuery">IQuery</see> interface. This query is compiled and used
		/// to retrieve the object from the storage.
		/// </param>
		public virtual T GetObject<T>(PersistentTypeSelector typeSelector, IQuery query)
		{
			using (ObjectReader<T> objectReader = this.GetObjectReader<T>(query))
			{
				// Register the event with the ObjectReader.
				objectReader.FetchingStorageRecord += typeSelector;

				if (!objectReader.Read())
				{
					Tracing.Current.TraceStorageIO("No object found to load.");
					return default(T);
				}
				return objectReader.Current;
			}
		}

		#endregion

		#region Synchronize

		/// <summary>
		/// Synchronizes the target with the data that has been given with the template.
		/// </summary>
		/// <remarks>
		/// This method synchronizes the mapped data of the target persistent object with the data that has been given 
		/// with the template persistent object. The synchronization will only apply as a flat synchronization; that means
		/// that related objects won't be synchronized.
		/// </remarks>
		/// <param name="targetPersistent">The persistent that is synchronized with the data from the template persistent.</param>
		/// <param name="templatePersistent">The persistent holds the data that is put into the target persistent.</param>
		public void Synchronize(object targetPersistent, object templatePersistent)
		{
			if (targetPersistent == null)
				throw new ArgumentNullException("targetPersistent");
			if (templatePersistent == null)
				throw new ArgumentNullException("templatePersistent");
			if (targetPersistent.GetType() != templatePersistent.GetType())
				throw new InvalidOperationException("The two persistents need to be of the same type.");

			// Get the type mapping.
			TypeMapping mapping = TypeMapping.GetTypeMapping(targetPersistent);
			
			// Copy the mapped members.
			IMemberInfoCollection members = mapping.Members;
			foreach (IMemberInfo member in members)
			{
				object value = member.GetValue(templatePersistent);
				member.SetValue(targetPersistent, value);
			}
		}

		#endregion

		#region Reload

		/// <summary>
		/// Reloads the given persistent object from the storage. Returns true if the reload was successful or
		/// false if not.
		/// </summary>
		/// <param name="obj">The persistent object that is reloaded from the storage.</param>
		/// <param name="ignoreCache">True to ignore the cache (if one has been set by using the CacheManager property of the ObjectContext).</param>
		/// <returns>True if the persistent object has been reloaded sucessfully; false if not.</returns>
		public bool Reload<T>(T obj, bool ignoreCache)
		{
			return Reload<T>(obj, ignoreCache, true);
		}

		/// <summary>
		/// Reloads the given persistent object from the storage. Returns true if the reload was successful or
		/// false if not.
		/// </summary>
		/// <param name="obj">The persistent object that is reloaded from the storage.</param>
		/// <returns>True if the persistent object has been reloaded sucessfully; false if not.</returns>
		public bool Reload<T>(T obj)
		{
			return Reload<T>(obj, false);
		}

		/// <summary>
		/// Reloads the given persistent object from the storage. Returns true if the reload was successful or
		/// false if not.
		/// </summary>
		/// <param name="obj">The persistent object that is reloaded from the storage.</param>
		/// <param name="ignoreCache">True to ignore the cache (if one has been set by using the CacheManager property of the ObjectContext).</param>
		/// <param name="invalidateRelations">True to invalidate all the relations. That means that related objects are also reloaded when requested for the next time.</param>
		/// <returns>True if the persistent object has been reloaded sucessfully; false if not.</returns>
		public bool Reload<T>(T obj, bool ignoreCache, bool invalidateRelations)
		{
			TypeMapping mapping = TypeMapping.GetTypeMapping(typeof(T));

			// get the identifiers of the object.
			IIdentifierMemberInfoCollection identifier = mapping.Members.GetIdentifierMemberMappings();
			// create the query to reload an object with the same identifiers.
			ObjectQueryBuilder<T> builder = new ObjectQueryBuilder<T>();
			foreach (IMemberInfo member in identifier)
			{
				builder.AppendProperty(member.Name, Comparisons.Equals, member.GetValue(obj));
			}

			// remove the object from the identity map. only the object itself is removed because
			// otherwise it is very time consuming to restore all the related objects in the identity
			// map if the re-load of the object wasn't successful. See underneath.
			if (this.IdentityMap.Enabled)
				this.IdentityMap.Remove(obj);

			T result = default(T);
			// get the object from the storage.
			using (ObjectReader<T> reader = this.GetObjectReader<T>(builder.ToObjectQuery(), ignoreCache))
			{
				// Get the first result.
				if (reader.MoveNext())
					result = reader.Current;
			}

			// if the object couldn't be reloaded return false.
			if (result == null)
			{
				// add the object again, if we couldn't load it from the storage.
				if (this.IdentityMap.Enabled)
					this.IdentityMap.Add(obj);
				return false;
			}

			// synchronize the two objects.
			this.Synchronize(obj, result);
			// copy the ObjectInfo object from the reloaded object to the current instance.
			this.SetObjectInfo(obj, this.GetObjectInfo(result));

			if (invalidateRelations)
			{
				// remove the whole loaded object graph from the identity map.
				if (this.IdentityMap.Enabled)
					this.IdentityMap.Remove(obj, true);

				// invalidate all relations.
				mapping.Relations.InvalidateAll(obj);
			}

			// add the object again to make sure it is present in the identity map.
			if (this.IdentityMap.Enabled)
				this.IdentityMap.Add(obj);
			return true;
		}

		#endregion

		#region PersistChanges

		/// <summary>
		/// Persists the changes on a single persistent object, an <see cref="ObjectSet{T}">ObjectSet</see> and 
		/// a class that implements the <see cref="ICustomPersister">ICustomPersister</see> interface.
		/// </summary>
		/// <remarks>
		/// This routine persists the changes on one single persistent object, an <see cref="ObjectSet{T}">ObjectSet</see> and 
		/// a class that implements the <see cref="ICustomPersister">ICustomPersister</see> interface. Some times you need
		/// to save only one single object in the storage. Use this routine if you have only one persistent object to be saved.
		/// Don't use this routine for lists of objects (except the <see cref="ObjectSet{T}">ObjectSet</see>) or non persistent 
		/// objects (if they don't implement <see cref="Opf3.ICustomPersister">ICustomPersister</see>).
		/// </remarks>
		/// <example>
		///     The following example shows you how to persist a single persistent object. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the first user matching the name.
		/// User user = context.GetObject&lt;User&gt;("Name like {0}", "%mith%");
		///  
		/// // Changes the name property.
		/// user.Name = "new Name";
		///  
		/// // Persists the user object.
		/// context.PersistChanges(user);
		///     </code>
		/// </example>
		/// <param name="obj">Persistent object, <see cref="ObjectSet{T}">ObjectSet</see> or class that implements 
		/// the <see cref="ICustomPersister">ICustomPersister</see> interface that is persisted.</param>
		/// <exception cref="Opf3.ConstraintException">A mandatory property of one persistent object returned Null.</exception>
		/// <exception cref="Opf3.Concurrency.ConcurrencyException">Somebody else changed the object in the storage
		/// while it has been in memory.</exception>
		/// <exception cref="Opf3.Storages.StorageException">Indicates a problem with the storage. All derived exception 
		/// may also be thrown.</exception>
		public virtual void PersistChanges<T>(T obj)
		{
			PersistChanges<T>(obj, PersistDepths.FullObjectGraph);
		}

		/// <summary>
		/// Persists the changes on a single persistent object, an <see cref="ObjectSet{T}">ObjectSet</see> and 
		/// a class that implements the <see cref="ICustomPersister">ICustomPersister</see> interface.
		/// </summary>
		/// <remarks>
		/// This routine persists the changes on one single persistent object, an <see cref="ObjectSet{T}">ObjectSet</see> and 
		/// a class that implements the <see cref="ICustomPersister">ICustomPersister</see> interface. Some times you need
		/// to save only one single object in the storage. Use this routine if you have only one persistent object to be saved.
		/// Don't use this routine for lists of objects (except the <see cref="ObjectSet{T}">ObjectSet</see>) or non persistent 
		/// objects (if they don't implement <see cref="Opf3.ICustomPersister">ICustomPersister</see>).
		/// </remarks>
		/// <example>
		///     The following example shows you how to persist a single persistent object. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the first user matching the name.
		/// User user = context.GetObject&lt;User&gt;("Name like {0}", "%mith%");
		///  
		/// // Changes the name property.
		/// user.Name = "new Name";
		///  
		/// // Persists the user object.
		/// context.PersistChanges(user);
		///     </code>
		/// </example>
		/// <param name="obj">Persistent object, <see cref="ObjectSet{T}">ObjectSet</see> or class that implements 
		/// the <see cref="ICustomPersister">ICustomPersister</see> interface that is persisted.</param>
		/// <param name="persistDepth">Specifies the depth of the object graph that is persisted.</param>
		/// <exception cref="Opf3.ConstraintException">A mandatory property of one persistent object returned Null.</exception>
		/// <exception cref="Opf3.Concurrency.ConcurrencyException">Somebody else changed the object in the storage
		/// while it has been in memory.</exception>
		/// <exception cref="Opf3.Storages.StorageException">Indicates a problem with the storage. All derived exception 
		/// may also be thrown.</exception>
		public virtual void PersistChanges<T>(T obj, PersistDepths persistDepth)
		{
			if (obj == null)
			{
				Tracing.Current.TraceWarning("Obj is null. Left without doing anything.");
				return;
			}

			try
			{
				ICustomPersister customPersister = obj as ICustomPersister;
				if (customPersister != null)
				{
					// The object uses a special mode to persist.
					customPersister.Persist(this, persistDepth, _persistingTrace);
					return;
				}

				// Check if this is the entry point for the persist.
				bool entryPoint = (_persistingTrace.Count == 0);
				// If the object has been persisted earlier we leave.
				if (_persistingTrace.ContainsPersisted(obj, persistDepth))
					return;

				// Invoke the event that is fired before persisting.
				// ATTENTION: needs to be after the check for being in a circular reference
				// to avoid multiple calls for one object!
				OnPersisting(new BeforeObjectPersistingEventArgs(obj));

				PersistentOperations po = _persister.GetCurrentPersistentOperation(obj);

				// Connect the related objects.
				_relationsManager.ConnectRelated(obj);

				// Persist all related objects.
				if (!_persistingTrace.ContainsHoppedBy(obj, persistDepth))
				{
					// Trace the object from now on as hopped by.
					_persistingTrace.MarkHoppedBy(obj, persistDepth);
					_relationsManager.PersistRelated(obj, PersistRelationships.ChildFirst, persistDepth, po);
				}

				// Check here again: The object could have been saved during PersistRelated.
				if (!_persistingTrace.ContainsPersisted(obj, persistDepth))
				{
					// The object is going to be saved. Trace it as saved.
					_persistingTrace.MarkPersisted(obj, persistDepth);

					// Persist the object.
					_persister.PersistChanges<T>(obj, persistDepth);
					// Connect the foreign key properties in the child objects with the identifier of this persistent.
					_relationsManager.ConnectPropertiesInChildObjects(obj);
					// Persist all related objects.
					_relationsManager.PersistRelated(obj, PersistRelationships.ParentFirst, persistDepth, po);
				}

				// Clear the trace if we are in the entry point.
				if (entryPoint)
					_persistingTrace.Clear();
			}
			catch
			{
				// Clear the persisting trace when we got an exception during save.
				_persistingTrace.Clear();
				throw;
			}
		}

		#endregion

		#region MarkForDeletion

		/// <summary>
		/// Marks a persistent object for deletion.
		/// </summary>
		/// <remarks>
		/// This routine marks a persistent object for deletion. The object
		/// is not deleted immediately. It is deleted on the next call of 
		/// <see cref="Opf3.ObjectContext.PersistChanges{T}(T)">PersistChanges</see>. 
		/// If you want to delete immediately an object from the storage you have
		/// to mark it for deletion and then call 
		/// <see cref="Opf3.ObjectContext.PersistChanges{T}(T)">PersistChanges</see>.
		/// </remarks>
		/// <example>
		///     The following example shows you how delete an object from the storage. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get the first user matching the name.
		/// User user = context.GetObject&lt;User&gt;("Name like {0}", "%mith%");
		///  
		/// // Mark the object for deletion.
		/// context.MarkForDeletion(user);
		///  
		/// // Deletes the user object from the storage.
		/// context.PersistChanges(user);
		///     </code>
		/// </example>
		/// <param name="obj">Persistent object that is marked for deletion.</param>
		public void MarkForDeletion(object obj)
		{
			if (obj == null)
			{
				Tracing.Current.TraceWarning("Obj is null. Left without doing anything.");
				return;
			}

			// Check if the object is a persistent object.
			if (TypeMapping.GetTypeMapping(obj) == null)
				throw new InvalidOperationException("A type that is no persistent object can't be marked for deletion.");

			// Invoke the event that is fired before marking an object for deletion.
			OnMarkingForDeletion(new MarkForDeletionEventArgs(obj));

			// Check if we have to notify the object about the change.
			ObjectNotificationEventArgs e = null;
			IObjectNotification objectNotification = obj as IObjectNotification;
			if (objectNotification != null)
			{
				e = new ObjectNotificationEventArgs(GetObjectInfo(obj), this, PersistentOperations.Load, PersistDepths.None);
				objectNotification.OnBeforeMarkDeleted(e);
			}

			// Mark the object for deletion.
			GetObjectInfo(obj).MarkForDeletion = true;

			// Invoke the event that is fired after marking the object for deletion.
			OnMarkedForDeletion(new MarkForDeletionEventArgs(obj));

			if (objectNotification != null)
				objectNotification.OnAfterMarkDeleted(e);
		}

		#endregion

		#region Transactions

		/// <summary>
		/// Starts a new transaction.
		/// </summary>
		/// <remarks>
		/// Starts a new transaction on the connected <see cref="Opf3.Storages.IStorage">IStorage</see>.
		/// This routine is only supported if the storage implements also the 
		/// <see cref="Opf3.Storages.ITransactionStorage">ITransactionStorage</see> interface.
		/// You don't get an exception if the storage does not support transactions and you call
		/// this routine.
		/// </remarks>
		/// <example>
		///     The following example shows how to use transaction management. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get an ObjectSet containing all user matching the name.
		/// // The result is sorted by Name.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;
		///     ("Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// // Change all names of the user objects.
		/// foreach(User user in objectSet)
		/// {
		///     user.Name = "new Name";
		/// }
		///  
		/// try
		/// {
		///     // Starts a new Transaction.
		///     using(Transaction t = context.StartTransaction())
		///     {
		///         // Deletes the user object from the storage.
		///         context.PersistChanges(objectSet);
		///  
		///         // Commit the changes to the storage.
		///         t.Commit();
		///     }
		/// }
		/// catch (Exception ex)
		/// {
		///     // Rolls the changes back.
		///     context.Rollback();
		///     Console.WriteLine("Error: " + ex.Message");
		/// }
		///     </code>
		/// </example>
		/// <returns>Returns an object that inherits of the abstract <see cref="Transaction">Transaction</see> class if the transaction 
		/// has been started sucessfully. Null otherwise.</returns>
		public Transaction StartTransaction()
		{
			ITransactionStorage transactionStorage = _storage as ITransactionStorage;
			if (transactionStorage != null)
			{
				return transactionStorage.StartTransaction();
			}

			Tracing.Current.TraceVerbose("Could not start a transaction. Storage does not implement the appropriate interface.");
			return null;
		}

		/// <summary>
		/// Starts a new transaction.
		/// </summary>
		/// <remarks>
		/// Starts a new transaction on the connected <see cref="Opf3.Storages.IStorage">IStorage</see>.
		/// This routine is only supported if the storage implements also the 
		/// <see cref="Opf3.Storages.ITransactionStorage">ITransactionStorage</see> interface.
		/// You don't get an exception if the storage does not support transactions and you call
		/// this routine.
		/// </remarks>
		/// <example>
		///     The following example shows how to use transaction management. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get an ObjectSet containing all user matching the name.
		/// // The result is sorted by Name.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;
		///     ("Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// // Change all names of the user objects.
		/// foreach(User user in objectSet)
		/// {
		///     user.Name = "new Name";
		/// }
		///  
		/// try
		/// {
		///     // Starts a new Transaction.
		///     using(Transaction t = context.StartTransaction())
		///     {
		///         // Deletes the user object from the storage.
		///         context.PersistChanges(objectSet);
		///  
		///         // Commit the changes to the storage.
		///         t.Commit();
		///     }
		/// }
		/// catch (Exception ex)
		/// {
		///     // Rolls the changes back.
		///     context.Rollback();
		///     Console.WriteLine("Error: " + ex.Message");
		/// }
		///     </code>
		/// </example>
		/// <returns>Returns an object that inherits of the abstract <see cref="Transaction">Transaction</see> class if the transaction 
		/// has been started sucessfully. Null otherwise.</returns>
		public Transaction StartTransaction(IsolationLevel level)
		{
			ITransactionStorage transactionStorage = _storage as ITransactionStorage;
			if (transactionStorage != null)
			{
				return transactionStorage.StartTransaction(level);
			}

			Tracing.Current.TraceVerbose("Could not start a transaction. Storage does not implement the appropriate interface.");
			return null;
		}

		/// <summary>
		/// Commits the current transaction.
		/// </summary>
		/// <remarks>
		/// Commits an open transaction on the connected <see cref="Opf3.Storages.IStorage">IStorage</see>.
		/// This routine is only supported if the storage implements also the 
		/// <see cref="Opf3.Storages.ITransactionStorage">ITransactionStorage</see> interface.
		/// You don't get an exception if the storage does not support transactions and you call
		/// this routine.
		/// </remarks>
		/// <example>
		///     The following example shows how to use transaction management. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get an ObjectSet containing all user matching the name.
		/// // The result is sorted by Name.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;
		///     ("Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// // Change all names of the user objects.
		/// foreach(User user in objectSet)
		/// {
		///     user.Name = "new Name";
		/// }
		///  
		/// // Starts a new Transaction.
		/// context.StartTransaction();
		///  
		/// try
		/// {
		///     // Deletes the user object from the storage.
		///     context.PersistChanges(objectSet);
		///  
		///     // Commit the changes to the storage.
		///     context.Commit();
		/// }
		/// catch (Exception ex)
		/// {
		///     // Rolls the changes back.
		///     context.Rollback();
		///     Console.WriteLine("Error: " + ex.Message");
		/// }
		///     </code>
		/// </example>
		/// <exception cref="Exception">No transaction active.</exception>
		[Obsolete("Please use the Transaction.Commit method instead of this method.")]
		public void Commit()
		{
			ITransactionStorage transactionStorage = _storage as ITransactionStorage;
			if (transactionStorage != null)
			{
				// Commit the current transaction.
				transactionStorage.Commit();
			}
			else
			{
				Tracing.Current.TraceVerbose("Could not commit transaction. Storage does not implement the appropriate interface.");
			}
		}

		/// <summary>
		/// Rolls the current transaction back.
		/// </summary>
		/// <remarks>
		/// Rolls the current transaction on the connected <see cref="Opf3.Storages.IStorage">IStorage</see>
		/// back. This routine is only supported if the storage implements also the 
		/// <see cref="Opf3.Storages.ITransactionStorage">ITransactionStorage</see> interface.
		/// You don't get an exception if the storage does not support transactions and you call
		/// this routine.
		/// </remarks>
		/// <example>
		///     The following example shows how to use transaction management. 
		///     <code lang="CS">
		/// // Creates a new ObjectContext that uses an MsSql Server as storage.
		/// ObjectContext context = new ObjectContext(new MsSqlStorage("sa", "", 
		///     "localhost", "application"));
		///  
		/// // ... Other code.
		///  
		/// // Get an ObjectSet containing all user matching the name.
		/// // The result is sorted by Name.
		/// ObjectSet&lt;User&gt; objectSet = context.GetObjectSet&lt;User&gt;
		///     ("Name like {0} SortBy Name Asc", "%mith%");
		///  
		/// // Change all names of the user objects.
		/// foreach(User user in objectSet)
		/// {
		///     user.Name = "new Name";
		/// }
		///  
		/// // Starts a new Transaction.
		/// context.StartTransaction();
		///  
		/// try
		/// {
		///     // Deletes the user object from the storage.
		///     context.PersistChanges(objectSet);
		///  
		///     // Commit the changes to the storage.
		///     context.Commit();
		/// }
		/// catch (Exception ex)
		/// {
		///     // Rolls the changes back.
		///     context.Rollback();
		///     Console.WriteLine("Error: " + ex.Message");
		/// }
		///     </code>
		/// </example>
		/// <exception cref="Exception">No transaction active.</exception>
		[Obsolete("Please use the Transaction.Rollback method instead of this method.")]
		public void Rollback()
		{
			ITransactionStorage transactionStorage = _storage as ITransactionStorage;
			if (transactionStorage != null)
			{
				// Roll the current transaction back.
				transactionStorage.Rollback();
			}
			else
			{
				Tracing.Current.TraceVerbose("Could not rollback transaction. Storage does not implement the appropriate interface.");
			}
		}

		#endregion

		#region Events

		/// <summary>
		/// Event fired before an object is updated.
		/// </summary>
		/// <remarks>
		/// This event is fired before an object is updated in the storage.
		/// It may be used if you want to customize the <see cref="Opf3.Query.IQuery">IQuery</see>
		/// for the operation.
		/// </remarks>
		public event EventHandler<ObjectPersistingEventArgs> Updating;

		/// <summary>
		/// Event fired after an object is updated.
		/// </summary>
		/// <remarks>
		/// This event is fired after an object has been updated in the storage.
		/// </remarks>
		public event EventHandler<ObjectPersistedEventArgs> Updated;

		/// <summary>
		/// Event fired before an object is inserted.
		/// </summary>
		/// <remarks>
		/// This event is fired before an object is inserted into the storage.
		/// It may be used if you want to customize the <see cref="Opf3.Query.IQuery">IQuery</see>
		/// for the operation.
		/// </remarks>
		public event EventHandler<ObjectPersistingEventArgs> Inserting;

		/// <summary>
		/// Event fired after an object is inserted.
		/// </summary>
		/// <remarks>
		/// This event is fired after an object has been inserted to the storage.
		/// </remarks>
		public event EventHandler<ObjectPersistedEventArgs> Inserted;

		/// <summary>
		/// Event fired before an object is deleted.
		/// </summary>
		/// <remarks>
		/// This event is fired before an object is deleted from the storage.
		/// It may be used if you want to customize the <see cref="Opf3.Query.IQuery">IQuery</see>
		/// for the operation.
		/// </remarks>
		public event EventHandler<ObjectPersistingEventArgs> Deleting;

		/// <summary>
		/// Event fired after an object is deleted.
		/// </summary>
		/// <remarks>
		/// This event is fired after an object has been deleted in the storage.
		/// </remarks>
		public event EventHandler<ObjectPersistedEventArgs> Deleted;

		/// <summary>
		/// Invoked before an object is inserted into the storage.
		/// </summary>
		/// <param name="e">EventArgs of the routine.</param>
		protected virtual void OnInserting(ObjectPersistingEventArgs e)
		{
			if (Inserting != null)
				Inserting(this, e);
		}

		/// <summary>
		/// Invoked after an object is inserted into the storage.
		/// </summary>
		/// <param name="e">EventArgs of the routine.</param>
		protected virtual void OnInserted(ObjectPersistedEventArgs e)
		{
			if (Inserted != null)
				Inserted(this, e);
		}

		/// <summary>
		/// Invoked before an object is updated in the storage.
		/// </summary>
		/// <param name="e">EventArgs of the routine.</param>
		protected virtual void OnUpdating(ObjectPersistingEventArgs e)
		{
			if (Updating != null)
				Updating(this, e);
		}

		/// <summary>
		/// Invoked after an object is updated in the storage.
		/// </summary>
		/// <param name="e">EventArgs of the routine.</param>
		protected virtual void OnUpdated(ObjectPersistedEventArgs e)
		{
			if (Updated != null)
				Updated(this, e);
		}

		/// <summary>
		/// Invoked before an object is deleted in the storage.
		/// </summary>
		/// <param name="e">EventArgs of the routine.</param>
		protected virtual void OnDeleting(ObjectPersistingEventArgs e)
		{
			if (Deleting != null)
				Deleting(this, e);
		}

		/// <summary>
		/// Invoked after an object is deleted from the storage.
		/// </summary>
		/// <param name="e">EventArgs of the routine.</param>
		protected virtual void OnDeleted(ObjectPersistedEventArgs e)
		{
			if (Deleted != null)
				Deleted(this, e);
		}

		#region Persister handler

		/// <summary>
		/// Invoked before deleting an object.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void persister_Deleting(object sender, ObjectPersistingEventArgs e)
		{
			OnDeleting(e);
		}

		/// <summary>
		/// Invoked before inserting an object.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void persister_Inserting(object sender, ObjectPersistingEventArgs e)
		{
			OnInserting(e);
		}

		/// <summary>
		/// Invoked before updating an object.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void persister_Updating(object sender, ObjectPersistingEventArgs e)
		{
			OnUpdating(e);
		}

		/// <summary>
		/// Invoked after updating an object.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void persister_Updated(object sender, ObjectPersistedEventArgs e)
		{
			OnUpdated(e);
		}

		/// <summary>
		/// Invoked after inserting an object.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void persister_Inserted(object sender, ObjectPersistedEventArgs e)
		{
			OnInserted(e);
		}

		/// <summary>
		/// Invoked after deleting an object.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void persister_Deleted(object sender, ObjectPersistedEventArgs e)
		{
			OnDeleted(e);
		}

		#endregion

		#region Load event + Reader handler

		/// <summary>
		/// Invoked each time after loading an object.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void reader_Loaded(object sender, ObjectLoadedEventArgs e)
		{
			OnLoaded(e);
		}

		/// <summary>
		/// Invoked each time before loading an object.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void reader_Loading(object sender, ObjectLoadingEventArgs e)
		{
			OnLoading(e);
		}

		/// <summary>
		/// Invoked after an object is loaded from the storage.
		/// </summary>
		/// <param name="e">EventArgs of the routine.</param>
		protected virtual void OnLoaded(ObjectLoadedEventArgs e)
		{
			if (Loaded != null)
				Loaded(this, e);
		}

		/// <summary>
		/// Invokes the event that is fired before an object has been loaded from the storage.
		/// </summary>
		/// <param name="e">The EventArgs for the event.</param>
		protected virtual void OnLoading(ObjectLoadingEventArgs e)
		{
			if (Loading != null)
				Loading(this, e);
		}

		/// <summary>
		/// Event fired before an object is loaded. The persistent is populated
		/// after this event has been fired!
		/// </summary>
		/// <remarks>
		/// This event is fired before an object has been loaded from the storage. The persistent is populated
		/// after this event has been fired!
		/// </remarks>
		public event EventHandler<ObjectLoadingEventArgs> Loading;

		/// <summary>
		/// Event fired after an object is loaded.
		/// </summary>
		/// <remarks>
		/// This event is fired after an object has been loaded from the storage.
		/// </remarks>
		public event EventHandler<ObjectLoadedEventArgs> Loaded;
		
		#endregion

		/// <summary>
		/// Event fired before an object is persisted (inserted, updated or deleted).
		/// </summary>
		/// <remarks>
		/// This event is fired before an object is persisted in the storage.
		/// </remarks>
		public event EventHandler<BeforeObjectPersistingEventArgs> Persisting;

		/// <summary>
		/// Invoked before an object is persisted in the storage.
		/// </summary>
		/// <param name="e">EventArgs of the routine.</param>
		protected virtual void OnPersisting(BeforeObjectPersistingEventArgs e)
		{
			if (Persisting != null)
				Persisting(this, e);
		}

		/// <summary>
		/// Event fired before an object is marked for deletion.
		/// </summary>
		/// <remarks>
		/// This event is fired before an object is marked for deletion in the storage.
		/// </remarks>
		public event EventHandler<MarkForDeletionEventArgs> MarkingForDeletion;

		/// <summary>
		/// Invoked before an object is marked for deletion in the storage.
		/// </summary>
		/// <param name="e">EventArgs of the routine.</param>
		protected virtual void OnMarkingForDeletion(MarkForDeletionEventArgs e)
		{
			if (MarkingForDeletion != null)
				MarkingForDeletion(this, e);
		}

		/// <summary>
		/// Event fired after an object is marked for deletion.
		/// </summary>
		/// <remarks>
		/// This event is fired before an object is marked for deletion in the storage.
		/// </remarks>
		public event EventHandler<MarkForDeletionEventArgs> MarkedForDeletion;

		/// <summary>
		/// Invoked after an object is marked for deletion in the storage.
		/// </summary>
		/// <param name="e">EventArgs of the routine.</param>
		protected virtual void OnMarkedForDeletion(MarkForDeletionEventArgs e)
		{
			if (MarkedForDeletion != null)
				MarkedForDeletion(this, e);
		}

		#endregion

		#region IDisposable Members

		/// <summary>
		/// Disposes the instance of the <see cref="ObjectContext">ObjectContext</see>.
		/// </summary>
		/// <param name="disposing">True to do only managed resources disposing.</param>
		protected virtual void Dispose(bool disposing)
		{
			if (!_disposed)
			{
				if (disposing)
				{
					if (_instancesCache != null)
						_instancesCache.Dispose();
				}

				_disposed = true;
			}
		}

		/// <summary>
		/// Disposes the instance of the <see cref="ObjectContext">ObjectContext</see>.
		/// </summary>
		void IDisposable.Dispose()
		{
			Dispose(true);
		}

		#endregion
	}
}